import { defineComponent, computed, ref, watch, reactive, unref, provide, createVNode } from 'vue';
import 'cui-vue-icons/feather';

const MenuContext = Symbol('MenuContext');
const MenuTreeContext = Symbol('MenuTreeContext');
const index = /* @__PURE__ */ defineComponent({
  name: 'Menu',
  props: {
    accordion: {
      type: Boolean,
      default: false
    },
    theme: {
      type: String,
      default: 'light'
    },
    dir: {
      type: String,
      default: 'v'
    },
    min: {
      type: Boolean,
      default: false
    },
    activeName: {
      type: [String, Object]
    },
    openKeys: {
      type: Array
    }
  },
  emits: ['select', 'update:activeName'],
  setup(props, {
    emit,
    slots
  }) {
    const accordion = () => props.accordion || false;
    const theme = () => props.theme || 'light';
    const dir = () => props.dir || 'v';
    const classList = computed(() => ({
      'cm-menu': true,
      [`cm-menu-${dir()}`]: dir(),
      [`cm-menu-min`]: props.min,
      [`cm-menu-${theme()}`]: theme()
    }));
    const tree = [];
    const treeMap = {};
    const openKeys = ref({});
    watch(() => props.openKeys, openedKeys => {
      const map = {};
      openedKeys.forEach(key => {
        map[key] = true;
      });
      openKeys.value = map;
    });
    watch(() => props.activeName, name => {
      store.activeName = name;
    });
    // 创建存储
    const store = reactive({
      activeName: props.activeName,
      min: props.min
    });
    watch(() => store.activeName, name => {
      if (name) {
        // 父节点没打开的话进行打开
        // 页面刷新的时候初始化需要延迟等待treeMap加载数据
        updateParentOpenStatus(name);
      }
    });

    // 更新min参数的副作用
    watch(() => props.min, min => {
      store.min = min;
    });

    // 更新父菜单的打开状态
    const updateParentOpenStatus = name => {
      let parent = treeMap && treeMap[name] && treeMap[name].parent;
      const oKs = unref(openKeys);
      if (parent) {
        while (parent) {
          if (!oKs[parent.name]) {
            setOpen(parent.name);
          }
          parent = parent.parent;
        }
      } else {
        // 顶级菜单项 横向的时候， 设置打开项 可以关闭已打开的subMenu
        if (dir() === 'h' || store.min) {
          setOpen(name);
        }
      }
    };

    // 菜单点击处理
    const onSelect = (name, data) => {
      store.activeName = name;
      emit('update:activeName', name);
      emit('select', name, data);
    };

    // 子菜单是否存在已打开的
    const childrenOpen = (item, names) => {
      const oKs = unref(openKeys);
      item.children && item.children.forEach(aitem => {
        if (oKs[aitem.name]) {
          names[aitem.name] = true;
        }
        childrenOpen(aitem, names);
      });
    };

    // 设置打开
    const setOpen = name => {
      const oKs = unref(openKeys);
      if (accordion() || dir() === 'h' || store.min) {
        if (accordion() && oKs[name]) {
          delete oKs[name];
          openKeys.value = {
            ...oKs
          };
          return;
        }
        let item = treeMap[name];
        const names = {
          [name]: true
        };
        while (item.parent) {
          names[item.parent.name] = true;
          item = item.parent;
        }
        childrenOpen(item, names);
        const keys = Object.keys(oKs);
        keys.forEach(key => {
          if (!names[key]) {
            delete oKs[key];
          }
        });
        openKeys.value = {
          ...names
        };
      } else {
        if (oKs[name]) {
          delete oKs[name];
        } else {
          oKs[name] = true;
        }
        openKeys.value = {
          ...oKs
        };
      }
    };
    provide(MenuContext, {
      padding: 16,
      onSelect,
      openKeys,
      store,
      setOpen,
      tree,
      treeMap,
      theme: theme(),
      dir: dir()
    });
    provide(MenuTreeContext, {
      padding: 0
    });
    return () => createVNode("ul", {
      "class": classList.value,
      "x-padding": 0,
      "x-name": "__root",
      "x-level": 0
    }, [slots.default && slots.default()]);
  }
});

export { MenuContext, MenuTreeContext, index as default };
